#ifndef ANET_H
#define ANET_H

#include <QDebug>
#include <QImage>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;

struct Strides
{
    int X;//水平步长
    int Y;//竖直步长
};

struct PoolSize
{
    int X;//水平步长
    int Y;//竖直步长
};

enum Padding {valid, same};

struct Conv_Layer{
    vector<vector<vector<double>>> input;//输入图像 inChannels * h*w
    int height;//输入图像的高
    int width;//输入图像的宽
    int inChannels;//输入图像的通道、个数

    //输入卷积核 outChannels * inChannels * x*y
    vector<vector<vector<vector<double>>>> kernels;
    int kernels_Height;//卷积核高
    int kernels_Width;//卷积核宽

    Strides strides;//水平 垂直步长
    Padding padding;//填充方式

    int pad_X;//水平填充圈
    int pad_Y;//竖直填充圈

    int outChannels;//输出图像的通道、个数(前面参数计算得到)

    vector<double> bias;//偏置 outchannels个
    bool activation; //是否激活函数

    vector<vector<vector<double>>> y; //未经过激活函数
    vector<vector<vector<double>>> d; //局部梯度
    vector<vector<vector<double>>> Y; //激活之后
};

struct Pool_Layer{
    int height;
    int width;
    int inChannels;
    int outChannels;

    PoolSize poolSize;//池化的长宽
    Strides strides;//池化的步长

    vector<vector<vector<double>>> y;//输出
    vector<vector<vector<double>>> d;//局部梯度
    vector<vector<vector<double>>> maxPosition;//最大池化的最大位置  标记
};

struct Out_Layer{
    int height;
    int width;
    int inChannels;

    vector<double> x;//将c*h*w 转为一维向量
    int neuronsNums;//神经元个数
    vector<vector<double>> w;//权值   neuronsNums * x.size()
    vector<double> bias;//偏置 等于神经元个数


    vector<double> d;//局部梯度
    vector<double> y;//未经过softmax层 输出
    vector<double> Y;//经过softmax层 输出
};

struct Net{
    Conv_Layer C1;
    Pool_Layer P2;
    Conv_Layer C3;
    Pool_Layer P4;
    Out_Layer O5;
};


class Anet
{
public:
    Anet();
    Conv_Layer ConvLayerInit(int inChannels, int inHeight, int inWidth,\
                             int outChannels, int kernelHeight, int kernelWidth,\
                             Strides strides,\
                             Padding padding);
    Pool_Layer PoolLayerInit(int inChannels, int inHeight, int inWidth,\
                             PoolSize poolSize,\
                             Strides strides);
    Out_Layer OutLayerInit(int inChannels, int inHeight, int inWidth,int neuronsNums);

    Net Init();

    void convN(vector<vector<vector<double>>> input, Conv_Layer &cN);
    void poolN(vector<vector<vector<double>>> input, Pool_Layer &pN);
    void fc(vector<vector<vector<double>>> input, Out_Layer &oL);

    void bp(Net &net, vector<double> t);
    void updataPara(Net &net, double study, vector<double> t);
    void show(Net net);
};

#endif // ANET_H
